/*
Copyright (C) <2011>  <ivan vaccari>

    <ivan.vaccari@studenti.unipr.it>


This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.


*/
#include "turingMachine.h"
#include <string>
#include <iostream>
#include <list>
turingMachine::turingMachine(turingConfiguration _cfg):currentSymbol("$"),cfg(_cfg),verbose(false),printseparator(true),configSetted(true){
}
turingMachine::turingMachine():currentSymbol("$"),verbose(false),printseparator(true),configSetted(false){
}
void turingMachine::setConfiguration(turingConfiguration _cfg){
    cfg=_cfg;
    configSetted=true;
}
void turingMachine::explodeOnTape(const std::string & _tape,std::list<std::string> & _t){

    if (_tape.length()>0){
        size_t posinit=0;
        size_t posfinal=_tape.find(',');


        if (posfinal==std::string::npos){
            _t.push_back(_tape);
        }else{
            while(true){
                _t.push_back(_tape.substr(posinit,posfinal-posinit));
                posinit=posfinal+1;
                posfinal=_tape.find(',',posinit);
                if (posfinal==std::string::npos){
                    std::string symbol=_tape.substr(posinit);
                    if (symbol.empty()){
                        throw "The tape has an empty symbol! Tape initialization aborted.";
                    }
                    _t.push_back(symbol);
                    break;
                }

            }
        }
    }
}
void turingMachine::setTapeRight(const std::string & _tape){
    explodeOnTape(_tape,tapeRight);
}
void turingMachine::setVerbose(bool v){
    verbose=v;
}
void turingMachine::setPrintSeparator(bool v){
    printseparator=v;
}
void turingMachine::setTapeLeft(const std::string & _tape){
    explodeOnTape(_tape,tapeLeft);
}
void turingMachine::setFirstSymbol(const std::string & symb){
    currentSymbol=symb;
}
std::list<std::string> turingMachine::getTapeLeft() const{
    return tapeLeft;
}
std::list<std::string> turingMachine::getTapeRight() const{
    return tapeRight;
}
std::string turingMachine::getFirstSymbol() const{
    return currentSymbol;
}
void turingMachine::printTape(){

    std::cout<<"$";
    if(printseparator)std::cout<<",";
    for(std::list<std::string>::const_iterator i=tapeLeft.begin();i!=tapeLeft.end();++i){
        std::cout<<*i;
        if(printseparator)std::cout<<",";

    }
    std::cout<<"["<<currentSymbol<<"]";
    if(printseparator)std::cout<<",";
    for(std::list<std::string>::const_iterator i=tapeRight.begin();i!=tapeRight.end();++i){
        std::cout<<*i;
        if(printseparator)std::cout<<",";
    }
    std::cout<<"$"<<std::endl;
}

void turingMachine::compute(){

    if (configSetted){
        std::string currentState=cfg.getInitialState();
        if (verbose){
            std::cout <<"Current state: "<<currentState<<", readed symbol: "<<currentSymbol<<std::endl;
        }
        while(true){

            instruction i;
            if (!cfg.findInstruction(currentState,currentSymbol,i)){
                if (verbose){
                    std::cout <<"Execution terminated. No instruction found for state '"<<currentState<<"' and symbol '"<<currentSymbol<<"'"<<std::endl;
                }
                return;
            }else{
                if (verbose){
                    printTape();
                    std::cout <<"Next state:"<<i.getNextState()<<", symbol to write: "<<i.getSymbolToWrite();
                    std::cout <<", move to: ";
                    if (i.moveLeft())
                        std::cout <<"L "<<std::endl;
                    else
                        std::cout <<"R "<<std::endl;
                }

                currentState=i.getNextState();
                currentSymbol=i.getSymbolToWrite();
                if (i.moveLeft()){
                    tapeRight.push_front(currentSymbol);
                    if (tapeLeft.size()>0){
                        currentSymbol=tapeLeft.back();
                        tapeLeft.pop_back();
                    }else{
                        currentSymbol="$";
                    }
                }else{
                    tapeLeft.push_back(currentSymbol);
                    if (tapeRight.size()>0){
                        currentSymbol=tapeRight.front();
                        tapeRight.pop_front();
                    }else{
                        currentSymbol="$";
                    }
                }
                if (verbose){
                    printTape();
                    std::cout <<std::endl<<std::endl<<"Current state: "<<currentState<<", readed symbol: "<<currentSymbol<<std::endl;


                }
            }
        }
    }else{
        throw "No configuration setted.";
    }
}



